
// Copyright (c) WanSheng Intelligent Corp. All rights reserved.
// Licensed under the LGPL v3.0 license. 


#include <stdbool.h>
#include <linux/prctl.h>

#include "modbus_plugin.h"
#include "modbus_module.h"
#include "logs.h"
#include "path.h"
#include "ams_constants.h"
#include "modbus.h"
#include "file_util.h"
#include "wa_edge_configs.h"
wa_plugin_device_info_t* g_devices_info = NULL;
int g_devices_info_size = 0;

static i_modbus_t* plugin_create_modbus(wa_bus_info_t* bus_info)
{
    extern unsigned char log_level;
    modbus_t* ctx = NULL;
    if (T_Bus_Serials == bus_info->bus_type)
    {
        char parity = 'N';
        int bits = 8;
        int stop = 1;
        if (bus_info->serials_addr.mode != NULL)
        {
            int mode_len = strlen(bus_info->serials_addr.mode);
            if (mode_len == 1)
                parity = bus_info->serials_addr.mode[0];
            else if (mode_len == 3) {
                parity = bus_info->serials_addr.mode[1];
                bus_info->serials_addr.mode[1] = 0;
                bits = atoi(bus_info->serials_addr.mode);
                stop = atoi(bus_info->serials_addr.mode + 2);
            }
        }
        ctx = modbus_new_rtu(bus_info->serials_addr.serials_port_name,
            bus_info->serials_addr.baud_rate, parity, bits, stop);

    }
    else if (T_Bus_TCP == bus_info->bus_type) {
        ctx = modbus_new_tcp(bus_info->tcp_addr.ip, bus_info->tcp_addr.port);
    }
    else
    {
        WARNING("cann't create modbus. modbus type <%d> was not supported.", bus_info->bus_type);
        return NULL;
    }

    if (NULL == ctx)
    {
        ERROR("Modbus create Context Error!");
        return NULL;
    }

    i_modbus_t* bus = (i_modbus_t*)malloc(sizeof(i_modbus_t));
    memset(bus, 0, sizeof(i_modbus_t));
    bus->addr = bus_info;
    bus->bus_ctx = ctx;

    modbus_set_error_recovery(ctx, (modbus_error_recovery_mode)(MODBUS_ERROR_RECOVERY_PROTOCOL));
    modbus_set_response_timeout(ctx, 0, 500 * 1000);
    if (LOG_VERBOSE == log_level)
    {
        modbus_set_debug(ctx, TRUE);
    }
    else
    {
        modbus_set_debug(ctx, FALSE);
    }

    if (bus_info->timeout_s != 0 || bus_info->timeout_us != 0)
    {
        bus->response_wait_ms = bus_info->timeout_s * 1000 + bus_info->timeout_us / 1000;
        WARNING("bus response_wait_ms: %d", bus->response_wait_ms);
        modbus_set_response_timeout(bus->bus_ctx, bus_info->timeout_s, bus_info->timeout_us);
    }

    bus->status = S_Bus_Disconnected;
    bus->min_wait_ms = bus_info->min_wait_ms;

    add_modbus(bus);

    return bus;
}


static i_modbus_device_t* plugin_setup_device(wa_plugin_device_info_t* info, i_modbus_t* bus)
{
    bool meta_miss_load = true;
    i_modbus_device_t* device = (i_modbus_device_t*)malloc(sizeof(i_modbus_device_t));
    if (device == NULL)
    {
        WARNING2("malloc fail!");
        return NULL;
    }
    memset(device, 0, sizeof(i_modbus_device_t));
    device->bus = bus;
    device->slave_id = info->device_ID;
    device->id = strdup(info->device_name);
    return device;
}


bool load_plugin_device_cfg(const char * plugin_name)
{
    char buf[256];
    int device_num = 0;
    WARNING("Start loading modbus config...");

    assert(g_devices_info == NULL);

    wa_plugin_device_info_t* devices_info = wa_plugin_load_device_info_A(plugin_name, &device_num);

    if (devices_info == NULL)
    {
        WARNING2("load cfg fail");
        return false;
    }

    for (int k = 0; k < device_num; k++)
    {
        wa_plugin_device_info_t* info = &devices_info[k];
        if (find_mb_device(info->device_name))
        {
            WARNING2("device %s already add. skip current.", info->device_name);
            continue;
        }
        if (info->device_ID < 0)
        {
            WARNING2("slave ID invalid");
            continue;
        }

        i_modbus_t* bus = NULL;
        if (info->bus_info->bus_type == T_Bus_Serials)
        {
            bus = find_modbus_by_info(info->bus_info);
        }

        if (bus == NULL)
        {
            bus = plugin_create_modbus(info->bus_info);
            WARNING("created a new bus [%s] %s for modbus tcp from modbus.cfg", 
                    info->bus_info->bus_name, bus != NULL ? "success" : "fail");
            if (bus == NULL) continue;
        }

        i_modbus_device_t* device = plugin_setup_device(info,  bus);
        if (device)
        {
            add_device(device);
            WARNING2("added a new device [%s] at sid %d", info->device_name, info->device_ID);
        }
    }

    g_devices_info = devices_info;
    g_devices_info_size = device_num;

    WARNING("Finished loading modbus plugin config\n");
    return true;
}

